package testFaceJNI;

import net.gdface.image.LazyImage;

import net.gdface.image.UnsupportedFormatException;
import net.zyface.zyfacesdk.jna.*;

import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;

import java.io.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

/*
 * 	int ZY_GetDevicesSerialNumber(ByteBuffer EncryptionSerial, ByteBuffer mac, ByteBuffer cardstype);
 *   The ZY_GetDevicesSerialNumber function will get the PC info and turn to EncryptionSerial,the EncryptionSerial
 *   must be given back to ZYTECHNOLOGY to get the decryptSerial code

	*Parameters:
	*EncryptionSerial[output],new [128] char* in
	*mac[output],new [128] char* in
	*cardstype[output] new [128] char* in
	*error code:
	*FACE_ERROR_SERAIL_P					-401
	*FACE_SUCESS                 0
	*Remarks:
	*This function only can be called one time at program first used.
 */
/*
 * int ZY_FaceSDKInit(int nChannelNums, ByteBuffer decryptSerial);
 * 	The ZY_FaceSDKInit function will initialize the algorithm engine module
	must be given back to ZYTECHNOLOGY to get the decryptSerial code

	Parameters:
	nChannelNums[intput],algorithm channel nums,for multi-thread mode,one thread uses one channel
	decryptSerial[intput],the decryptSerial code get from ZYTECHNOLOGY
	error code:
	FACE_SUCESS                 0

	FACE_ERROR_INITFAILED      -1
	FACE_ERROR_MAXCHANNEL         -6
	FACE_REPEAT_INITFAILED      -9
	FACE_ERROR_SERAIL_P					-401
	FACE_ERROR_DECRYPT_P				-402
	FACE_ERROR_TIMEOUT					-403
	FACE_ERROR_LOCAL_DECRYPT_P			-404
	FACE_ERROR_LOCAL_DECRYPT_FILE_P      -405
	FACE_ERROR_COMPARE_DECRYPT_FILE_P    -406
	FACE_ERROR_NO_DECRYPT_P				-407
	Remarks:
	This function only can be called one time at  program initialization.
 */

/*
 * int ZY_DetectAndExtract(ByteBuffer pdata, int width, int height, int channel, ByteBuffer pFea);
 * The ZY_DetectAndExtract function execute face detection and get face feature.

	Parameters:
	pdata[input],image data buffer,RGB24 format.
	width[input],image width.
	height[input],image height.
	channel[input],bits per pixel(24-RGB24 image),must be 24
	pFea[output],the face feature..
	Return Values:
	If the function succeeds, the return value is FACE_SUCESS
	If the function fails, the return value is negative.
	error code:
	FACE_SUCESS                 0
	FACE_ERROR_INITFAILED      -1
	FACE_ERROR_MAXCHANNEL         -6
	FACE_REPEAT_INITFAILED      -9
	FACE_ERROR_SERAIL_P					-401
	FACE_ERROR_DECRYPT_P				-402
	FACE_ERROR_TIMEOUT					-403
	FACE_ERROR_LOCAL_DECRYPT_P			-404
	FACE_ERROR_LOCAL_DECRYPT_FILE_P      -405
	FACE_ERROR_COMPARE_DECRYPT_FILE_P    -406
	FACE_ERROR_NO_DECRYPT_P				-407
	Remarks:
	1.image data buffer(pImage)	size must be nWidth*(bpp/8)*nHeight.
	2.pFea must be allocated by caller,the memory size is FATURE_SIZE
	3.image data  have only have one face in
 */
/*
 * int ZY_FaceSDKRelease()
 * 	The ZY_FaceSDKRelease function will release the algorithm engine module
	Parameters:
	No parameter.
	Return Values:
	No return value.
	Remarks:
	This function only can be called one time at program exit.
 */

public class Test {
	final int FACE_SUCESS = 0;// 返回成功

	final int FACE_ERROR_INITFAILED = -1;// 初始化失败
	final int FACE_REPEAT_INITFAILED = -9;// 重复初始化
	final int FACE_ERROR_INPUTDATAERROR = -2;
	final int FACE_ERROR_WRONGPARM = -3;
	final int FACE_ERROR_OTHERERROR = -4;
	final int FACE_ERROR_LOADMODELFAILED = -5;
	final int FACE_ERROR_MAXCHANNEL = -6; // 初始化超过最大路数
	final int FACE_ERROR_FEATRRELENTH = -7;
	final int FACE_ERROR_NOFACES = -8;// 当前照片没有人脸

	final int FACE_ERROR_SERAIL_P = -401; // 获取系列号错误
	final int FACE_ERROR_DECRYPT_P = -402;//// 授权不通过
	final int FACE_ERROR_TIMEOUT = -403;
	final int FACE_ERROR_LOCAL_DECRYPT_P = -404;// 授权不通过
	final int FACE_ERROR_LOCAL_DECRYPT_FILE_P = -405;// 授权不通过
	final int FACE_ERROR_COMPARE_DECRYPT_FILE_P = -406;// 授权不通过
	final int FACE_ERROR_NO_DECRYPT_P = -407;

	/**
	 * 多线程测试
	 * 
	 * @throws InterruptedException
	 */
	public static void test7MultiThreadDetectFace() throws InterruptedException {// 多线程测试
		ExecutorService executor = new ThreadPoolExecutor(8, 8, 0, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(),
				new ThreadFactoryBuilder().setNameFormat("cached-pool-%d").build());
		final String[] images = new String[] {
				"/media/gdface/3056dc96-13de-46f7-bb2a-e9ff29693ab1/SDK/FaceSDKForWinCmake/FaceSDKForWin/build/test/bin/1.jpg",
				"/media/gdface/3056dc96-13de-46f7-bb2a-e9ff29693ab1/SDK/FaceSDKForWinCmake/FaceSDKForWin/build/test/bin/2.jpg" };
		for (int i = 0; i < 200; ++i) {
			final String f = images[i % 2];
			File filea = new File(f);
			BufferedImage imagea = null;
			try {
				imagea = ImageIO.read(filea);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			LazyImage lazyImage = LazyImage.create(imagea);
			final byte[] bgr;
			final int imagewidth = imagea.getWidth();
			final int imageheight = imagea.getHeight();
			try {
				bgr = lazyImage.getMatrixBGR();// 获取BGR数据
			} catch (UnsupportedFormatException e) {
				throw new RuntimeException(e);
			}
			executor.execute(new Runnable() {
				@Override
				public void run() {
					try {
						ByteBuffer fea = ByteBuffer.allocate(FaceSDKForWinLibrary.FATURE_SIZE);
						int flag = FaceSDKForWinLibrary.INSTANCE.ZY_DetectAndExtract(ByteBuffer.wrap(bgr), imagewidth,
								imageheight, 3, fea);

						System.out.println(flag);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}
		executor.shutdown();
		while (!executor.isTerminated()) {
			executor.awaitTermination(10, TimeUnit.SECONDS);
		}
	}

	public static void testSingleThreadDetectFaceAndExtract() // 单线程测试
	{
		String filePathA = "/media/gdface/3056dc96-13de-46f7-bb2a-e9ff29693ab1/SDK/FaceSDKForWinCmake/FaceSDKForWin/build/test/bin/1.jpg";
		File filea = new File(filePathA);
		BufferedImage imagea = null;
		try {
			imagea = ImageIO.read(filea);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		LazyImage lazyImage = LazyImage.create(imagea);
		byte[] bgr;
		try {
			bgr = lazyImage.getMatrixBGR();// 获取BGR数据
		} catch (UnsupportedFormatException e) {
			throw new RuntimeException(e);
		}
		ByteBuffer fea = ByteBuffer.allocate(FaceSDKForWinLibrary.FATURE_SIZE);
		int flag = FaceSDKForWinLibrary.INSTANCE.ZY_DetectAndExtract(ByteBuffer.wrap(bgr), imagea.getWidth(),
				imagea.getHeight(), 3, fea);// 检测并返回人脸特征 特征铲长度为 FATURE_SIZE

		System.out.println(flag);

	}

	public static void main(String[] args) throws IOException {

		// System.loadLibrary("FS_FaceDetec_InfJNI");
		// System.loadLibrary("FS_FaceRecog_InfJNI");
		// System.loadLibrary("FS_FaceSrcCount");

		byte[] encryptSerial = new byte[129];

		ByteBuffer EncryptionSerial = ByteBuffer.wrap(encryptSerial);

		// int getserial =
		FaceSDKForWinLibrary.INSTANCE.ZY_GetDevicesSerialNumber(EncryptionSerial); //
		// 获取机器码

		System.out.println(new String(EncryptionSerial.array()));// 需要提供给中运科技获取授权

		/////////////////////////////////// 上面需要单独运行//////////////////

		String decryptSerial = "3vfY60AI3ycLAb3Asr3YbZ3MpvrkxZsNwusNcBFYUbWpY6UpImcYQHV4Uof6T=";
		decryptSerial = decryptSerial + "\0";
		// 中运科技提供的授权码
		byte[] decryptSerialby = decryptSerial.getBytes();
		// ByteBuffer decryptSerialbf = ByteBuffer.allocate(128);
		int initFlag = FaceSDKForWinLibrary.INSTANCE.ZY_FaceSDKInit(8, ByteBuffer.wrap(decryptSerialby)); // 申请8路处理
		// 内部有多线程处理机制，最多处理8路
		System.out.println(initFlag);

		// testSingleThreadDetectFaceAndExtract();// 测试单线程

		try {
			test7MultiThreadDetectFace(); // 测试多线程
		} catch (InterruptedException e) { // TODO Auto-generated catch block
			e.printStackTrace();
		}

		int test = FaceSDKForWinLibrary.INSTANCE.ZY_FaceSDKRelease();// 释放资源，退出的时候调用
		System.out.println(test);

	}

}
